package HashMap.Nodo.Operaciones;

import HashMap.Nodo.Clase;
import HashMap.Nodo.Nodo;
import HashMap.Nodo.Operacion;
import HashMap.Nodo.Subclases.VectorPropio;
import HashMap.Nodo.TipoBasicoDeDatos;
import HashMap.GenerarCodigoNASM;
import HashMap.Nodo.Categoria;
import HashMap.Nodo.Subclases.Escalar;
import HashMap.Pila;

public class OperacionesDeVectores implements Operacion {

    private VectorPropio nodo1;
    private Nodo nodo2;
    private Nodo nodo3;
    private Nodo nodoDefinitivo;

    public OperacionesDeVectores(Nodo nodo1, Nodo nodo2) {
        this.nodo1 = (VectorPropio) nodo1;
        this.nodo2 = nodo2;
    }

    public OperacionesDeVectores(Nodo nodo1, Nodo nodo2, Nodo nodo3) {
        this.nodo1 = (VectorPropio) nodo1;
        this.nodo2 = nodo2;
        this.nodo3 = nodo3;
    }

    @Override
    public int getLongitud() {
        throw new UnsupportedOperationException("Operacion no soportada");
    }

    @Override
    public String generarCodigoNASM() {
        switch (nodo1.getOperacion()) {
            case "VECTOR1D":
                return generarCodigoNASMvector1D();
            case "VECTOR2D":
                return generarCodigoNASMvector2D();
            default:
                return null;
        }
    }

    @Override
    public Nodo generarNodo(String tokenOperacion) {
        switch (tokenOperacion) {
            case "VECTOR1D":
                return vector1D();
            case "VECTOR2D":
                return vector2D();
            default:
                return null;
        }
    }

    private boolean condicionesVector1D() {
        if (nodo1.getClase() == Clase.VECTOR) {
            VectorPropio vectorAux = (VectorPropio) nodo1;
            return vectorAux.getDimension() == 1 && nodo2.getTipoBasicoDeDatos() == TipoBasicoDeDatos.INT
                    && (nodo2.getNivelDeIndireccion() == 0 || nodo2.getNivelDeIndireccion() == 1);
        }
        return false;
    }

    private boolean condicionesVector2D() {
        if (nodo1.getClase() == Clase.VECTOR) {
            VectorPropio vectorAux = (VectorPropio) nodo1;
            return vectorAux.getDimension() == 1
                    && nodo2.getTipoBasicoDeDatos() == TipoBasicoDeDatos.INT
                    && nodo3.getTipoBasicoDeDatos() == TipoBasicoDeDatos.INT
                    && (nodo2.getNivelDeIndireccion() == 0 || nodo2.getNivelDeIndireccion() == 1)
                    && (nodo3.getNivelDeIndireccion() == 0 || nodo3.getNivelDeIndireccion() == 1);
        }
        return false;
    }

    private Nodo vector1D() {
        if (condicionesVector1D()) {
            nodo1.setOperacion("VECTOR1D");
            GenerarCodigoNASM generador = GenerarCodigoNASM.getInstancia();
            String nombre = generador.getNombreVariableAuxiliar();
            nodoDefinitivo = new Escalar(nombre, nodo1.getTipoBasicoDeDatos(), Categoria.VARIABLE, 0, "VECTOR1D");
            Pila.getInstancia().addNodoALaTablaSuperior(nodoDefinitivo);
            return nodoDefinitivo;
        }
        throw new IllegalArgumentException("No se están cumpliendo las "
                + "condiciones de los vectores de dimension 1");
    }

    private Nodo vector2D() {
        if (condicionesVector2D()) {
            nodo1.setOperacion("VECTOR2D");
            GenerarCodigoNASM generador = GenerarCodigoNASM.getInstancia();
            String nombre = generador.getNombreVariableAuxiliar();
            nodoDefinitivo = new Escalar(nombre, nodo1.getTipoBasicoDeDatos(), Categoria.VARIABLE, 0, "VECTOR2D");
            Pila.getInstancia().addNodoALaTablaSuperior(nodoDefinitivo);
            return nodoDefinitivo;
        }
        throw new IllegalArgumentException("No se están cumpliendo las "
                + "condiciones de los vectores de dimension 2");
    }

    private String generarCodigoNASMvector1D() {
        return "add " + nodo1.getNombre() + ", " + nodo2.getNombre()
                + "mov [" + nodoDefinitivo.getNombre() + "], " + nodo3.getNombre();
    }

    private String generarCodigoNASMvector2D() {
        return "mult " + nodo1.getNumeroDeColumnas() + ", [" + nodo2.getNombre() + "]\n"
                + "mov [aux1], [aux]\n"
                + "mult " + nodo1.getNumeroDeFilas() + ", [" + nodo3.getNombre() + "]\n"
                + "add [aux], [aux1]\n"
                + "add " + nodo1.getNombre() + ", [aux]\n"
                + "mov [" + nodoDefinitivo.getNombre() + "], " + nodo1.getNombre();
    }
}
